#include <atomic>
#include <chrono>
#include <ctime>
#include <functional>
#include <iostream>
#include <queue>
#include <string>
#include <thread>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include "json.hpp"
// Linux的网络通信所需库函数
#include <arpa/inet.h>
#include <netinet/in.h>
#include <semaphore.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

#include <mutex>

#include "public.h"
// 自定义的一些类所在的头文件
#include "group.h"
#include "user.h"
using Json = nlohmann::json;
using myClock = std::chrono::system_clock;

// 记录当前系统登录的用户信息
User g_currentUser;
// 记录当前登录用户的好友列表信息
std::vector<User> g_currentUserFriendList;
// 记录当前登录用户的群组列表信息
std::vector<Group> g_currentUserGroupList;
// 记录当前登录用户的离线消息
std::vector<std::string> g_currentUserOffMsg;

// 控制主菜单页面程序
bool isMainMenuRunning = false;
bool isHBTaskRunning = false;

// 用于读写线程之间的通信
sem_t rwsem;
// 记录登录状态
std::atomic_bool g_isLoginSuccess{false};
// time_t 类型的时间变量
time_t lastSendTime;
// 时间变量会涉及到并发修改，上锁
std::mutex timeMtx;

// 接收线程：这个线程只是用于接收服务端发送的数据，并不会在这个线程中发送数据。
void readTaskHandler(int clientfd);
// 心跳线程：在这个线程中，每隔一秒，轮询一次，是否需要发送心跳包
void heartBeatHandler(int clientFd);
// 主聊天页面程序
void mainMenu(int);
// 显示当前登录成功用户的基本信息
void showCurrentUserData();
// 处理注册的响应消息函数
void doRegResponse(Json &response);
// 处理登录的响应消息函数
void doLoginResponse(Json &response);
// 命令函数的声明
void help(int clientFd = 0, std::string command = "");
void chat(int clientFd, std::string command);
void addfriend(int clientFd, std::string command);
void creategroup(int clientFd, std::string command);
void addgroup(int clientFd, std::string command);
void groupchat(int clientFd, std::string command);
void logout(int clientFd, std::string command);
void showFriendList(int clientFd = 0, std::string command = "");
void showGroupList(int clientFd = 0, std::string command = "");
void showOffMsgList(int clientFd = 0, std::string command = "");

// 获取当前用户的好友列表
void getFriendList(Json &response, std::vector<User> &fredList);
// 获取当前用户的群组列表
void getGroupList(Json &response, std::vector<Group> &groupList);
// 获取当前用户的离线消息列表
void getOfflineMsgList(Json &response, std::vector<std::string> &offMsgList);

// 系统支持的客户端命令列表
std::unordered_map<std::string, std::string> commandMap = {
    {"help:", "显示所有支持的命令，格式: [help:]"},
    {"chat", "一对一聊天，格式: [chat:friendid:message]"},
    {"addfriend", "添加好友，格式: [addfriend:friendid]"},
    {"creategroup", "创建群组，格式: [creategroup:groupname:groupdesc]"},
    {"addgroup", "加入群组，格式: [addgroup:groupid]"},
    {"groupchat", "群聊，格式: [groupchat:groupid:message]"},
    {"logout", "注销，格式: [logout]"},
    {"s-f:", "[显示好友列表]"},
    {"s-g:", "[显示群组列表]"},
    {"s-off:", "[显示离线消息列表]"},
};

// 注册系统支持的客户端命令处理
std::unordered_map<std::string, std::function<void(int, std::string)>>
    commandHandlerMap = {{"help", help},           {"chat", chat},
                         {"addfriend", addfriend}, {"creategroup", creategroup},
                         {"addgroup", addgroup},   {"groupchat", groupchat},
                         {"logout", logout},       {"s-f", showFriendList},
                         {"s-g", showGroupList},   {"s-off", showOffMsgList}};

/*
保证消息按序传输
*/
// 创建两张表
// 以userID为key，seq和ack组成的pair为value的一个哈希表map。记录和userID的好友通信的seq和ack的
// 自定义一些数据结构，方便后续的开发
struct SAnum {
    int seq;
    int ack;
    SAnum() : seq(0), ack(0) {}
};
struct SeqString {
    int seq;
    std::string msgbody;
    SeqString(int n, const std::string &str) : seq(n), msgbody(str) {}
};

std::unordered_map<int, SAnum> oneChatSaMap;
std::unordered_map<int, SAnum> groupChatSaMap;
// 以userID为key，优先队列为value的一个哈希表

class MyCmp {
public:
    bool operator()(const SeqString &lhs, const SeqString &rhs) {
        return lhs.seq > rhs.seq;
    }
};

std::unordered_map<
    int, std::priority_queue<SeqString, std::vector<SeqString>, MyCmp>>
    oneChatMsgCacheMap;
std::unordered_map<
    int, std::priority_queue<SeqString, std::vector<SeqString>, MyCmp>>
    groupChatMsgCacheMap;
/************************* 主程序 *****************************/

int main(int argc, char const *argv[]) {
    if (argc < 3) {
        std::cerr << "command invalid! example: ./client 127.0.0.1 6000"
                  << std::endl;
        exit(-1);  // 退出程序
    }
    // 获取IP地址和端口号
    const char *IP = argv[1];
    const uint16_t PORT = atoi(argv[2]);
    // 下面是客户端使用原生的linux进行socket通信

    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == sockfd) {
        std::cerr << "socket create error" << std::endl;
        exit(-1);
    }
    // 填写要访问的服务器的结构体
    struct sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(PORT);
    inet_pton(AF_INET, IP, &serverAddr.sin_addr.s_addr);
    // 客户端主动发起连接
    int ret =
        connect(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
    if (-1 == ret) {
        std::cerr << "connect server error" << std::endl;
        close(sockfd);
        exit(-1);
    }
    // 初始化读写线程通信用的信号量
    sem_init(&rwsem, 0, 0);
    // 连接服务器成功，启动接收子线程
    std::thread readTask(readTaskHandler, sockfd);  // pthread_create

    // 设置线程分离，让操作系统自动回收资源
    readTask.detach();

    // 死循环
    while (true) {
        // 显示首页面菜单 登录、注册、退出
        std::cout << "========================" << std::endl;
        std::cout << "1. login" << std::endl;
        std::cout << "2. register" << std::endl;
        std::cout << "3. quit" << std::endl;
        std::cout << "========================" << std::endl;
        std::cout << "choice:";
        int choice = 0;
        std::cin >> choice;
        std::cin.get();  // 读掉缓冲区残留的回车
        switch (choice) {
            case 1: {
                /* 登录 */
                std::cout << "id:" << std::endl;
                int id;
                std::cin >> id;
                std::cout << "password:" << std::endl;
                std::string pwd;
                std::cin >> pwd;
                Json request;
                request[MSG_TYPE_ID] = LOG_IN;
                request[SEND_ID] = id;
                request[PWD] = pwd;
                std::string message = request.dump();
                int ret = send(sockfd, message.c_str(),
                               strlen(message.c_str()) + 1, 0);
                if (-1 == ret) {
                    std::cerr << "send login msg error:" << message
                              << std::endl;
                }
                // rwsem信号量初始值为0
                // 只有在接收子线程中，成功的登录或者注册上之后，rwsem才会变为1，这里才会解锁
                sem_wait(&rwsem);

                if (g_isLoginSuccess) {
                    isMainMenuRunning = true;
                    lastSendTime = time(nullptr);
                    isHBTaskRunning = true;
                    std::thread heartBeatTask(heartBeatHandler, sockfd);
                    heartBeatTask.detach();
                    mainMenu(sockfd);
                    // 启动心跳报文发送线程
                    
                }
                break;
            }
            case 2: {
                /* 注册 */
                std::cout << "name:" << std::endl;
                std::string name;
                std::cin >> name;
                std::cout << "password:" << std::endl;
                std::string pwd;
                std::cin >> pwd;
                Json request;
                request[MSG_TYPE_ID] = REG;
                request[NAME] = name;
                request[PWD] = pwd;

                std::string message = request.dump();
                int ret = send(sockfd, message.c_str(),
                               strlen(message.c_str()) + 1, 0);
                if (-1 == ret) {
                    std::cerr << "send reg msg error:" << message << std::endl;
                }
                sem_wait(&rwsem);

                break;
            }
            case 3:
                std::cout << "bye-bye" << std::endl;
                close(sockfd);
                sem_destroy(&rwsem);
                exit(0);
                break;

            default:
                std::cout << "invalid command, try again!" << std::endl;
                break;
        }
    }
    return 0;
}

// 接收线程
void readTaskHandler(int clientfd) {
    while (true) {
        // 最大只能接收8KB的数据，多了就不行了，这里要注意
        char buffer[8192] = {0};
        int len = recv(clientfd, buffer, sizeof(buffer), 0);  // 阻塞了
        if (-1 == len || 0 == len) {
            close(clientfd);
            exit(-1);
        }
        /*
        子线程接收来自服务器的消息
        服务器向客户端发送的JSON中，都带有一个msgid
        通过这个msgid，客户端可以用于判断此次接收到的JSON的内容
        */
        Json response = Json::parse(buffer);
        int msgType = response[MSG_TYPE_ID].get<int>();
        switch (msgType) {
            case REG_MSG_ACK: {
                doRegResponse(response);
                // 增加资源
                sem_post(&rwsem);
                break;
            }
            case LOG_IN_MSG_ACK: {
                doLoginResponse(response);
                // 增加资源
                sem_post(&rwsem);
                break;
            }
            case ONE_CHAT: {
                // 接收到了其他客户端发送来的聊天消息

                // 逻辑要更改
                // 如果之前没有和response[SEND_ID]
                // 表示的这个用户聊过天，初始化saMap
                int sendID = response[SEND_ID];

                // 开始对消息的序号进行判断
                if (oneChatSaMap[sendID].ack == response[MSG_SEQ]) {
                    oneChatSaMap[sendID].ack++;
                    std::cout << "one chat >>>\t"
                              << "time: " << response[TIME] << std::endl
                              << "user:[" << response[SEND_ID] << "]"
                              << " ---> "
                              << "message: " << response[MSG] << std::endl;
                    // 输出序列号
                    // std::cout << "msg-seq: " << response[MSG_SEQ] <<
                    // std::endl;
                } else {
                    // 缓存消息
                    oneChatMsgCacheMap[sendID].push(
                        SeqString(response[MSG_SEQ], response.dump()));
                }
                while (oneChatMsgCacheMap.count(sendID) &&
                       !oneChatMsgCacheMap[sendID].empty()) {
                    if (oneChatMsgCacheMap[sendID].top().seq ==
                        oneChatSaMap[sendID].ack) {
                        Json msgFromCache = Json::parse(
                            oneChatMsgCacheMap[sendID].top().msgbody);
                        oneChatMsgCacheMap[sendID].pop();
                        oneChatSaMap[sendID].ack++;
                        std::cout << "one chat >>>\t"
                                  << "time: " << msgFromCache[TIME] << std::endl
                                  << "user:[" << msgFromCache[SEND_ID] << "]"
                                  << " ---> "
                                  << "message: " << msgFromCache[MSG]
                                  << std::endl;
                    } else if (oneChatMsgCacheMap[sendID].top().seq <
                               oneChatSaMap[sendID].ack) {
                        // 也许会存在一种bad
                        // case：消息堆的堆顶的seq小于期望接收的
                        // 我个人认为这种情况是不会发生的
                        // 从优先队列中弹出，因为这条消息已经没有消费的意义了
                        oneChatMsgCacheMap[sendID].pop();
                    }
                    // 退出循环
                    else {
                        break;
                    }
                }
                // 同时也要去访问cache
                break;
            }
            case FRIEND_ONLINE: {
                // 朋友上线了
                std::cout << "friend online >>>\t"
                          << "time: " << response[TIME] << "\t"
                          << "friend[" << response[SEND_ID] << "]" << std::endl;
                int friendID = response[SEND_ID].get<int>();
                for (auto &iter : g_currentUserFriendList) {
                    if (iter.getId() == friendID) {
                        iter.setState("online");
                    }
                }
                break;
            }
            case FRIEND_OFFLINE: {
                // 朋友下线了
                std::cout << "friend offline >>>\t"
                          << "time: " << response[TIME] << "\t"
                          << "friend[" << response[SEND_ID] << "]" << std::endl;
                int friendID = response[SEND_ID].get<int>();
                for (auto &iter : g_currentUserFriendList) {
                    if (iter.getId() == friendID) {
                        iter.setState("offline");
                    }
                }
                break;
            }
            case ADD_FRIEND_ACK: {
                std::cout << "add friend >>>\t"
                          << "time: " << response[TIME]
                          << "\tinfo:" << response[MSG] << std::endl;
                int isSuccess = response[ERRNO].get<int>();
                if (isSuccess == 0) {
                    // 添加好友成功，将好友加入到现有的好友列表中
                    User frd;
                    frd.setId(response[SEND_ID].get<int>());
                    frd.setName(response[NAME]);
                    frd.setState(response[STATE]);
                    g_currentUserFriendList.push_back(frd);
                    // 还有需求要处理：a添加b为好友，修改了服务器上的好友信息，并且让客户端a上的好友列表加上了b
                    // 但是b也需要将a添加在客户端的好友列表中去
                }
                break;
            }
            case CREATE_GROUP_ACK: {
                // 创建群组
                std::cout << "create group >>>\t"
                          << "time: " << response[TIME]
                          << "\tinfo:" << response[MSG] << std::endl;
                if (response[ERRNO].get<int>() == 0) {
                    // 将新建的群组，添加到当前的群组列表中区
                    Group newgroup;
                    newgroup.setID(response[GROUP_ID].get<int>());
                    newgroup.setGName(response[GROUP_NAME]);
                    newgroup.setGDesc(response[GROUP_DESC]);
                    GroupUser gu;
                    gu.setId(g_currentUser.getId());
                    gu.setName(g_currentUser.getName());
                    gu.setState(g_currentUser.getState());
                    gu.setRole("creator");
                    newgroup.getUsers().push_back(gu);
                    g_currentUserGroupList.push_back(newgroup);
                }
                break;
            }
            case ADD_TO_GROUP_ACK: {
                // 添加到群组
                std::cout << "create group >>>\t"
                          << "time: " << response[TIME]
                          << "\tinfo:" << response[MSG] << std::endl;
                // 更新当前用户的群组列表
                if (response[ERRNO].get<int>() == 0) {
                    // 把新加入的群，更新在当前用户的群组列表中
                    Group group;
                    group.setID(response[GROUP_ID].get<int>());
                    group.setGName(response[GROUP_NAME]);
                    group.setGDesc(response[GROUP_DESC]);
                    std::vector<std::string> mems;
                    for (std::string &str : mems) {
                        Json guJs = Json::parse(str);
                        GroupUser gu;
                        gu.setId(guJs[SEND_ID].get<int>());
                        gu.setName(guJs[NAME]);
                        gu.setState(guJs[STATE]);
                        gu.setRole(guJs[GROUP_ROLE]);
                        group.getUsers().push_back(gu);
                    }
                    g_currentUserGroupList.push_back(group);
                }
                break;
            }
            case GROUP_CHAT: {
                // 按照onechat的逻辑，把接收到groupchat的动作重写一遍
                int sendID = response[SEND_ID];
                if (groupChatSaMap[sendID].ack == response[MSG_SEQ]) {
                    // 处理相应的逻辑
                }
                std::cout << "group chat >>>\t"
                          << "time: " << response[TIME] << std::endl
                          << "group:[" << response[GROUP_ID] << "]"
                          << "-"
                          << "user:[" << response[SEND_ID] << "]"
                          << " ---> "
                          << "message: " << response[MSG] << std::endl;
                break;
            }
            case LOG_OUT_ACK:{
                std::cout << "您已经下线了。。。请输入【quit:】结束" << std::endl;
                isMainMenuRunning = false;
                isHBTaskRunning = false;
                break;
            }
            default:
                std::cout << "Oops... unexcept event!" << std::endl;
                break;
        }
    }
}

void heartBeatHandler(int clientFd) {
    int cnt = 10;
    while (isHBTaskRunning) {
        sleep(1);

        {
            std::unique_lock<std::mutex> lk(timeMtx);
            time_t currTime = time(nullptr);
            if (currTime - lastSendTime >= 1) {
                // 发送心跳包
                Json ms;
                ms[MSG_TYPE_ID] = HEART_BEAT;
                ms[SEND_ID] = g_currentUser.getId();
                std::string msstr = ms.dump();
                int len = send(clientFd, msstr.c_str(), msstr.size(), 0);
                if (len < 0) {
                    std::cout << "发送心跳包失败" << std::endl;
                    // 结束子线程
                    return;
                }
                lastSendTime = time(nullptr);
            }
        }

        // cnt--;
    }
}

// 处理注册的响应消息函数
void doRegResponse(Json &response) {
    if (-1 == response["errno"].get<int>()) {
        std::cout << "register failed!" << std::endl;
        return;
    }
    // 注册成功
    std::cout << "name register success, userid is [" << response[SEND_ID]
              << "], do not forget it!" << std::endl;
}

// 处理登录的响应消息函数
void doLoginResponse(Json &response) {
    int state = response[ERRNO].get<int>();
    if (0 != state) {
        // 登录失败
        std::cerr << "login failed! " << response[MSG] << std::endl;
        g_isLoginSuccess = false;
        return;
    }
    // 登录成功
    
    g_currentUser.setId(response[SEND_ID].get<int>());
    g_currentUser.setName(response[NAME]);

    // 拉取好友列表、群组列表、离线消息
    g_currentUserFriendList.clear();  // 清除上一个用户保存的信息
    g_currentUserGroupList.clear();
    g_currentUserOffMsg.clear();

    getFriendList(response, g_currentUserFriendList);
    // 拉取群组列表
    getGroupList(response, g_currentUserGroupList);
    // 拉取离线消息
    getOfflineMsgList(response, g_currentUserOffMsg);

    // showOffMsgList();
    g_isLoginSuccess = true;
}

// 主聊天页面程序
void mainMenu(int clientFd) {
    help();  // 调用该函数，显示可以执行的命令
    // 获取命令
    char order[128] = {0};

    std::cin.get();  // 吃掉回车
    while (isMainMenuRunning) {
        // showCurrentUserData(); // 调用该函数，显示用户的好友、群组信息
        memset(order, 0, sizeof(order));
        std::cin.getline(order, sizeof(order));
        // std::cout << order << std::endl;
        // 获取具体的命令
        std::string command;
        for (char ch : order) {
            if (ch == ':' || ch == ' ') {
                break;
            }
            command += ch;
        }
        if (command == "quit" || command == "exit")
            break;
        else if (commandMap.count(command)) {
            auto func = commandHandlerMap.find(command)->second;
            // 执行相应功能的函数
            func(clientFd, order);
        } else {
            std::cout << "invalid command" << std::endl;
        }
    }
}
// 显示当前登录成功用户的基本信息
void showCurrentUserData() {
    // 显示好友列表
    std::cout << "friend list >>>" << std::endl;
    for (auto &iter : g_currentUserFriendList) {
        std::cout << "SEND_ID: " << iter.getId() << "\tName: " << iter.getName()
                  << "\tState: " << iter.getState() << std::endl;
    }

    // 显示群组列表
    std::cout << "group list >>>" << std::endl;
    for (auto &iter : g_currentUserGroupList) {
        std::cout << "group SEND_ID: " << iter.getID()
                  << "\tgroup name: " << iter.getGName()
                  << "\tgroup desc: " << iter.getGDesc() << std::endl;
        std::cout << "group members: " << std::endl;
        auto &members = iter.getUsers();
        for (auto &m : members) {
            std::cout << "\tID: " << m.getId() << "\tName: " << m.getName()
                      << "\tState: " << m.getState()
                      << "\tRole: " << m.getRole() << std::endl;
        }
    }

    // 离线消息？
    std::cout << "offline message >>>" << std::endl;
    for (auto &iter : g_currentUserOffMsg) {
        Json offmsg = Json::parse(iter);
        std::cout << "message: " << offmsg["body"]
                  << " from SEND_ID: " << offmsg["sourceID"] << std::endl;
    }
}

// 命令函数
void help(int, std::string) {
    // 提供给用户执行的命令
    std::cout << "show command list >>> " << std::endl;
    for (auto &p : commandMap) {
        std::cout << p.first << " :\t " << p.second << std::endl;
    }
    std::cout << std::endl;
}
void chat(int clientFd, std::string command) {
    // 解析command字符串
    std::string str1, str2, str3;
    int turn = 0;
    for (char ch : command) {
        if (ch == ':') {
            turn++;
        } else if (turn == 0) {
            str1 += ch;
        } else if (turn == 1) {
            str2 += ch;
        } else if (turn == 2) {
            str3 += ch;
        }
    }
    // print for test
    // std::cout << str1 << " " << str2 << " " << str3 << std::endl;
    int friendID = atoi(str2.c_str());
    // check friendID
    bool isIDLegal = false;
    for (auto &usr : g_currentUserFriendList) {
        if (usr.getId() == friendID) {
            isIDLegal = true;
            break;
        }
    }
    if (isIDLegal) {
        Json request;
        request[MSG_TYPE_ID] = ONE_CHAT;
        request[SEND_ID] = g_currentUser.getId();
        request[RECV_ID] = friendID;
        request[MSG_SEQ] = oneChatSaMap[friendID].seq++;
        request[MSG] = std::string(str3);
        request[TIME] = getCurrentTime();
        std::string message = request.dump();
        int len =
            send(clientFd, message.c_str(), strlen(message.c_str()) + 1, 0);
        if (-1 == len) {
            // 调用send函数发送到服务器【失败】
            std::cerr << "send to server failed!" << std::endl;
            return;
        }
        // 更新时间
        {
            std::unique_lock<std::mutex> lk(timeMtx);
            lastSendTime = time(nullptr);
        }
    } else {
        std::cout << "invalid id!" << std::endl;
        return;
    }
}
void addfriend(int clientFd, std::string command) {
    // 解析command字符串
    std::string str1, str2;
    int turn = 0;
    for (char ch : command) {
        if (ch == ':') {
            turn++;
        } else if (turn == 0) {
            str1 += ch;
        } else if (turn == 1) {
            str2 += ch;
        }
    }
    int fid = atoi(str2.c_str());
    Json request;
    request[MSG_TYPE_ID] = ADD_FRIEND;
    request[SEND_ID] = g_currentUser.getId();
    request[RECV_ID] = fid;
    std::string message = request.dump();
    /*
    添加好友会有如下两类unexpected event
        - 1. 输入的好友id【不存在】：这个需要服务器拉取user表查看id是否合法
        - 2. 输入的好友id【已经是好友】。这个在客户端中去检查
    */
    // 检查好友是否已经添加上了
    for (auto &iter : g_currentUserFriendList) {
        if (iter.getId() == fid) {
            // 查到添加上了
            std::cout << "add friend failed! already friend!" << std::endl;
            return;
        }
    }
    int len = send(clientFd, message.c_str(), strlen(message.c_str()) + 1, 0);
    if (-1 == len) {
        std::cerr << "send to server failed!" << std::endl;
        return;
    }
    // 更新时间
    {
        std::unique_lock<std::mutex> lk(timeMtx);
        lastSendTime = time(nullptr);
    }
}
void creategroup(int clientFd, std::string command) {
    // 解析command字符串
    std::string str1, str2, str3;
    int turn = 0;
    for (char ch : command) {
        if (ch == ':') {
            turn++;
        } else if (turn == 0) {
            str1 += ch;
        } else if (turn == 1) {
            str2 += ch;
        } else if (turn == 2) {
            str3 += ch;
        }
    }
    // std::cout << "creategroup..." << std::endl;
    Json request;
    request[MSG_TYPE_ID] = CREATE_GROUP;
    request[SEND_ID] = g_currentUser.getId();
    request[GROUP_NAME] = str2;
    request[GROUP_DESC] = str3;

    std::string message = request.dump();
    int len = send(clientFd, message.c_str(), strlen(message.c_str()) + 1, 0);
    if (-1 == len) {
        std::cerr << "send to server failed!" << std::endl;
        return;
    }
    // 更新时间
    {
        std::unique_lock<std::mutex> lk(timeMtx);
        lastSendTime = time(nullptr);
    }
}
void addgroup(int clientFd, std::string command) {
    // 解析command字符串
    std::string str1, str2;
    int turn = 0;
    for (char ch : command) {
        if (ch == ':') {
            turn++;
        } else if (turn == 0) {
            str1 += ch;
        } else if (turn == 1) {
            str2 += ch;
        }
    }
    // std::cout << "addgroup..." << std::endl;
    Json request;
    request[MSG_TYPE_ID] = ADD_TO_GROUP;
    int gid = atoi(str2.c_str());
    request[SEND_ID] = g_currentUser.getId();
    request[GROUP_ID] = gid;
    /*
    添加到群组中，也会有两类unexpected event
        - 1. 输入的群组id【不合法】。这只能由服务器帮我们检查合法性
        - 2. 已经在群组里了。客户端自己就可以检查
    */
    for (auto &iter : g_currentUserGroupList) {
        if (iter.getID() == gid) {
            std::cout << "add to group failed! you already in this group!"
                      << std::endl;
            return;
        }
    }
    std::string message = request.dump();
    int len = send(clientFd, message.c_str(), strlen(message.c_str()) + 1, 0);
    if (-1 == len) {
        std::cerr << "send to server failed!" << std::endl;
        return;
    }
    // 更新时间
    {
        std::unique_lock<std::mutex> lk(timeMtx);
        lastSendTime = time(nullptr);
    }
}
void groupchat(int clientFd, std::string command) {
    // 解析command字符串
    std::string str1, str2, str3;
    int turn = 0;
    for (char ch : command) {
        if (ch == ':') {
            turn++;
        } else if (turn == 0) {
            str1 += ch;
        } else if (turn == 1) {
            str2 += ch;
        } else if (turn == 2) {
            str3 += ch;
        }
    }
    // std::cout << "groupchat..." << std::endl;
    Json request;
    request[MSG_TYPE_ID] = GROUP_CHAT;
    int gid = atoi(str2.c_str());
    request[SEND_ID] = g_currentUser.getId();
    request[GROUP_ID] = gid;
    request[MSG] = str3;
    request[TIME] = getCurrentTime();
    // 判断输入的群号是否为自己的群
    for (auto &iter : g_currentUserGroupList) {
        if (iter.getID() == request[GROUP_ID]) {
            std::string message = request.dump();
            int len =
                send(clientFd, message.c_str(), strlen(message.c_str()) + 1, 0);
            if (-1 == len) {
                std::cerr << "send to server failed!" << std::endl;
            }
            // 更新时间
            {
                std::unique_lock<std::mutex> lk(timeMtx);
                lastSendTime = time(nullptr);
            }
            return;
        }
    }
    std::cerr << " U do not belong to this group!" << std::endl;
    return;
}
void logout(int clientFd, std::string) {
    std::cout << "logout..." << std::endl;
    // 客户端下线
    Json request;
    request[MSG_TYPE_ID] = LOG_OUT;
    request[SEND_ID] = g_currentUser.getId();
    std::string message = request.dump();
    int len = send(clientFd, message.c_str(), strlen(message.c_str()) + 1, 0);
    if (-1 == len) {
        std::cout << "send to server failed!" << std::endl;
        return;
    }
    isMainMenuRunning = false;
    isHBTaskRunning = false;
}

// 获取当前用户的好友列表
void getFriendList(Json &response, std::vector<User> &fredList) {
    if (response.contains(FRIEND_LIST)) {
        std::vector<std::string> friends = response[FRIEND_LIST];
        for (std::string &str : friends) {
            Json info = Json::parse(str);
            User usr;
            usr.setId(info[SEND_ID].get<int>());
            usr.setName(info[NAME]);
            usr.setState(info[STATE]);
            fredList.push_back(usr);
        }
    }
}
// 获取当前用户的群组列表
void getGroupList(Json &response, std::vector<Group> &groupList) {
    if (response.contains(GROUP_LIST)) {
        /*
        response["groups"] = {string, string...}
        string = oneGroupinfo.dump = {gid, name, desc, {usr...}}
        两次的序列化和反序列化
        */
        std::vector<std::string> groups = response[GROUP_LIST];
        for (std::string &str : groups) {
            Json info = Json::parse(str);
            Group oneGroup;
            oneGroup.setID(info[GROUP_ID]);
            oneGroup.setGName(info[GROUP_NAME]);
            oneGroup.setGDesc(info[GROUP_DESC]);
            std::vector<std::string> groupMem = info[GROUP_MEMS];
            for (std::string &mem : groupMem) {
                Json m = Json::parse(mem);
                GroupUser gusr;
                gusr.setId(m[SEND_ID]);
                gusr.setName(m[NAME]);
                gusr.setState(m[STATE]);
                gusr.setRole(m[GROUP_ROLE]);
                oneGroup.getUsers().push_back(gusr);
            }
            groupList.push_back(oneGroup);
        }
    }
}
// 获取当前用户的离线消息列表
void getOfflineMsgList(Json &response, std::vector<std::string> &offMsgList) {
    if (response.contains(OFF_MSG)) {
        std::vector<std::string> vec = (response[OFF_MSG]);
        offMsgList = vec;
    }
}

void showFriendList(int a, std::string s) {
    // 显示好友列表
    std::cout << "**********<< friend list >>**********" << std::endl;
    for (auto &iter : g_currentUserFriendList) {
        std::cout << "SEND_ID: " << iter.getId() << "\tName: " << iter.getName()
                  << "\tState: " << iter.getState() << std::endl;
    }
}
void showGroupList(int a, std::string s) {
    // 显示群组列表
    std::cout << "**********<< group list >>**********" << std::endl;
    for (auto &iter : g_currentUserGroupList) {
        std::cout << "group SEND_ID: " << iter.getID()
                  << "\tgroup name: " << iter.getGName()
                  << "\tgroup desc: " << iter.getGDesc() << std::endl;
        std::cout << "group members: " << std::endl;
        std::cout << "------------------------------------" << std::endl;
        auto &members = iter.getUsers();
        for (auto &m : members) {
            std::cout << "\tID: " << m.getId() << "\tName: " << m.getName()
                      << "\tState: " << m.getState()
                      << "\tRole: " << m.getRole() << std::endl;
        }
    }
}
void showOffMsgList(int clientFd, std::string command) {
    std::cout << "**********<< OfflineMessage list >>**********" << std::endl;
    for (auto &iter : g_currentUserOffMsg) {
        Json offmsg = Json::parse(iter);
        std::cout << "time: " << offmsg[TIME] << " ";
        if (offmsg.contains(GROUP_ID)) {
            std::cout << "group[" << offmsg[GROUP_ID] << "]-";
        }
        std::cout << "user[" << offmsg[SEND_ID] << "] ---> "
                  << "message: " << offmsg[MSG] << std::endl;
    }
}